{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 自编码器"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "生成模型的作用是学习一个概率分布$P_{model}(X)$并按这个概率分布生成数据"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. 自动编码器(Autoencoders)\n",
    "应用：1.数据去噪 2.可视化降维\n",
    "\n",
    "作为压缩算法的特点：\n",
    "1. 与数据相关程度很高，使用植物训练的自编码器用于提取动物的特征，会得到很差的结果\n",
    "2. 压缩编码后的数据是有损的\n",
    "<center>自动编码器</center>\n",
    "<img src='image/autoencoder.jpg' height='50%' width='50%'>\n",
    "上图是一个自编码器的整体架构图(出自CS231n课件)，损失函数是原图像与重构图像间的L2距离，编解码器均使用神经网络来实现"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.1 数据预处理"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import torch\n",
    "import numpy as np\n",
    "from torch import nn, optim\n",
    "import matplotlib.pyplot as plt\n",
    "from torch.autograd import Variable\n",
    "from torch.utils.data import DataLoader\n",
    "from torchvision import datasets, transforms\n",
    "from torchvision.utils import save_image\n",
    "\n",
    "use_cuda = torch.cuda.is_available()                    # gpu可用\n",
    "device = torch.device('cuda' if use_cuda else 'cpu')    # 优先使用gpu"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 设置超参数(Hyperparameters)\n",
    "batch_size = 128\n",
    "learning_rate = 1e-3\n",
    "num_epochs = 20"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 1.读取数据及预处理\n",
    "# Compose将各种预处理操作组合，ToTensor将图片处理为tensor，\n",
    "# Normalize(mean, variance)正则化\n",
    "data_tf = transforms.Compose([transforms.ToTensor(),                 # 数据变为tensor，范围[0,1]\n",
    "                              transforms.Normalize([0.5], [0.5])])   # 缩放到[-1,1]\n",
    "# 下载MNIST手写数字训练集\n",
    "train_dataset = datasets.MNIST(root='./data/MNIST', train=True, transform=data_tf, download=False)\n",
    "test_dataset = datasets.MNIST(root='./data/MNIST', train=False, transform=data_tf)\n",
    "# 创建数据迭代器便于训练模型\n",
    "train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, num_workers=4)#, pin_memory=True)\n",
    "test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.训练数据的维度:\n",
      "torch.Size([60000, 28, 28])\n",
      "torch.Size([60000])\n",
      "2.测试数据的维度:\n",
      "torch.Size([10000, 28, 28])\n",
      "torch.Size([10000])\n"
     ]
    }
   ],
   "source": [
    "print('1.训练数据的维度:')\n",
    "print(train_dataset.train_data.shape)\n",
    "print(train_dataset.train_labels.shape)\n",
    "print('2.测试数据的维度:')\n",
    "print(test_dataset.test_data.shape)\n",
    "print(test_dataset.test_labels.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.0~9样本的索引: [5, 9, 3, 0, 2, 14, 51, 1, 20, 17]\n"
     ]
    },
    {
     "data": {
      "image/png": "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arNXX311AC655BIgtJjdbbfdUj7i9Oy0005A5ZXrI4880uz9Nd+g+3sM3czMaiZXGbokV2Zdfvnlpd99+umnmRzDlltuWXE8RRtz1spWffUYeqC+L9qmTb1dkh566CEAhg8fns2BZUztgW+//XYgXIlUs/766wNw8sknA6Gfzi677AKEnjeqOisSZeJ6TVqfkZwv0TyCtjnUla76++jqJanp6vZqm2R0lDN0M7NI5DJD13+8448/Hijf5DZtv/71r4FQh9v0eIo65hzbhhYdoW3B9t9/f6B6Zi777bcfEHoDxUarGlu7ulGZpTLyU089FQi9c9SRVJtyA/zvf/+rzcFmTBm4Kp9effVVIMwjJNcoqF69aadWCJ1etQk7OEM3M7MW5DJDl3feeSez59KKOGXmymab+vzzzzM7nlpKjpnr56KuEO0IbRfWdCVwU5q3UTaV5XuwSHSVp55JytDV+VIrUAHuueeejI+ufZJ15erVMnToUKB6bf7MmTOBsJL0z3/+MxDq0pW5q9dLmpyhm5lFIlcZ+jPPPAOEHtaqR580aVLqz606W42xNmfUqFGpH0cakmPoWc5J5MUiiywCwMEHHzzP+6m/93nnnZf6McXoo48+AkJ1UBFonYY2hlen1Z49ewKw2GKLlf1+7NixQFjDoHkDbTxeT87QzcwikasMfc011wRC9zKt3EqDakXVm+OEE06oel/1j7n22mtTO540JcfQn3jiiXoeTqbU11vjmVtssUWz91MFQx5W+xWBaqrVd0l0Najde4pAtfUaG1dfmmTljypTRo4cCYSOr3nqje8M3cwsErnK0FVhoi6LXbt2BeC2224r3Wf06NFAy33Phw0bBoSucKppX3755YFQK5rsrCYPPvhg6XtlIVmtUq215Bh6Uevp26J79+5A6G1dLTMX7chz8803t+l5lM1BqIqYNm0aEN5DMdWwKzNXfX5yBW2yZ3gRqD+P9h3+4x//2Oz9FJdUyaM5P80b5IEzdDOzSDRkma01NDTM88m0C0q1/sPtfE6g9VnpXXfdBcDFF19cuq3pFUJrNDY2trpJSkvnpCPUQVBXKToX6mp50003pfXUFbI+J1oJWo/dpnRFNGLECKB6z/62nBNI971SjVZLqouislhVgMiMGTMA6NevX9nP7ZGXz0+S1qq89957APztb38DWr76q4XWnhNn6GZm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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x23cd1274be0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 显示数据\n",
    "%matplotlib inline\n",
    "def show_image():\n",
    "    test = test_dataset.test_labels.numpy()     # 将tensor数据转换为numpy数据\n",
    "    print(np.where(test==1))\n",
    "    sample_index = [np.where(test==i)[0][1] for i in range(10)] # np.where的输出(array([], dtype),)\n",
    "    print('1.0~9样本的索引:', sample_index)\n",
    "    sample_data = test_dataset.test_data[sample_index]          # 获取10个样本数据\n",
    "    print('2.手写体样本:')\n",
    "    for i in range(10):\n",
    "        plt.subplot(2,5,i+1)\n",
    "        sample_data = test_dataset.test_data[sample_index][i]    # torch.Size([28, 28])\n",
    "#         print(sample_data.shape)\n",
    "        plt.axis(\"off\")       # 关掉坐标轴\n",
    "        plt.imshow(sample_data, interpolation='none', cmap='gray')\n",
    "# show_image()\n",
    "def show_image2():\n",
    "#     x,y = train_loader.__iter__().next()   # 通过数据迭代器访问数据\n",
    "    x, y = next(train_loader.__iter__())\n",
    "    x, y = map(lambda x:x.numpy(), [x, y])   # 将tensor转换为numpy数据\n",
    "    sample_index = [np.where(y==i)[0][0] for i in range(10)]\n",
    "    print('1.0~9样本的索引:',sample_index)\n",
    "    for i in range(10):\n",
    "        plt.subplot(2,5,i+1)\n",
    "        sample_data = x[sample_index][i,0]    # (28,28)\n",
    "        plt.axis('off')\n",
    "        plt.imshow(sample_data, cmap='gray')\n",
    "show_image2()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.2 定义自编码器模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义模型\n",
    "class AutoEncoder(nn.Module):\n",
    "    def __init__(self):\n",
    "        super().__init__()                   # 继承类的初始化  \n",
    "        self.encoder = nn.Sequential(        # 编码器部分 input (N, 1, 28, 28)\n",
    "            nn.Linear(28*28, 128),           # (N, 128)\n",
    "            nn.ReLU(),\n",
    "            nn.Linear(128, 64),              # (N, 64)\n",
    "            nn.ReLU(),\n",
    "            nn.Linear(64, 12),               # (N, 12)\n",
    "            nn.ReLU(),\n",
    "            nn.Linear(12, 3)                 # (N, 3)   三个通道方便可视化\n",
    "        )\n",
    "        self.decoder = nn.Sequential(\n",
    "            nn.Linear(3, 12),                # (N, 12)\n",
    "            nn.ReLU(),\n",
    "            nn.Linear(12, 64),               # (N, 64)\n",
    "            nn.ReLU(),\n",
    "            nn.Linear(64, 128),              # (N, 128)\n",
    "            nn.Linear(128, 28*28),           # (N, 28*28)\n",
    "            nn.Tanh()                        # 将数据缩放到 (-1,1)，与输入的数据范围对应!!!\n",
    "        )\n",
    "    def forward(self, x):                    # 输入数据维度    (N, 1, 28, 28)\n",
    "        x_flatten = x.view(-1, 28*28)        # 将数据reshape为 (N, 28*28)\n",
    "        encode = self.encoder(x_flatten)     # 编码器\n",
    "        decode = self.decoder(encode)        # 解码器\n",
    "        decode = decode.view(x.size())       # (N, 1, 28, 28)\n",
    "        return encode, decode"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.3 添加损失、优化器并进行训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 设置损失函数及优化器\n",
    "autoencoder = AutoEncoder().to(device)\n",
    "# print(autoencoder)\n",
    "criterion = nn.MSELoss()        # 均方差损失就是L2距离损失\n",
    "optimizer = optim.Adam(autoencoder.parameters(), lr=learning_rate)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "------------Epoch:0-------------\n",
      "Iter:0     loss:0.9384\n",
      "Iter:468   loss:0.2056\n",
      "------------Epoch:1-------------\n",
      "Iter:0     loss:0.2126\n",
      "Iter:468   loss:0.1831\n",
      "------------Epoch:2-------------\n",
      "Iter:0     loss:0.1820\n",
      "Iter:468   loss:0.1801\n",
      "------------Epoch:3-------------\n",
      "Iter:0     loss:0.1650\n",
      "Iter:468   loss:0.1820\n",
      "------------Epoch:4-------------\n",
      "Iter:0     loss:0.1550\n",
      "Iter:468   loss:0.1556\n",
      "------------Epoch:5-------------\n",
      "Iter:0     loss:0.1552\n",
      "Iter:468   loss:0.1666\n",
      "------------Epoch:6-------------\n",
      "Iter:0     loss:0.1458\n",
      "Iter:468   loss:0.1619\n",
      "------------Epoch:7-------------\n",
      "Iter:0     loss:0.1556\n",
      "Iter:468   loss:0.1520\n",
      "------------Epoch:8-------------\n",
      "Iter:0     loss:0.1536\n",
      "Iter:468   loss:0.1471\n",
      "------------Epoch:9-------------\n",
      "Iter:0     loss:0.1410\n",
      "Iter:468   loss:0.1501\n",
      "------------Epoch:10-------------\n",
      "Iter:0     loss:0.1416\n",
      "Iter:468   loss:0.1339\n",
      "------------Epoch:11-------------\n",
      "Iter:0     loss:0.1374\n",
      "Iter:468   loss:0.1462\n",
      "------------Epoch:12-------------\n",
      "Iter:0     loss:0.1342\n",
      "Iter:468   loss:0.1404\n",
      "------------Epoch:13-------------\n",
      "Iter:0     loss:0.1486\n",
      "Iter:468   loss:0.1431\n",
      "------------Epoch:14-------------\n",
      "Iter:0     loss:0.1297\n",
      "Iter:468   loss:0.1435\n",
      "------------Epoch:15-------------\n",
      "Iter:0     loss:0.1510\n",
      "Iter:468   loss:0.1367\n",
      "------------Epoch:16-------------\n",
      "Iter:0     loss:0.1460\n",
      "Iter:468   loss:0.1299\n",
      "------------Epoch:17-------------\n",
      "Iter:0     loss:0.1406\n",
      "Iter:468   loss:0.1358\n",
      "------------Epoch:18-------------\n",
      "Iter:0     loss:0.1435\n",
      "Iter:468   loss:0.1369\n",
      "------------Epoch:19-------------\n",
      "Iter:0     loss:0.1403\n",
      "Iter:468   loss:0.1485\n",
      "Wall time: 1min 57s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "# 开始训练模型\n",
    "num_epochs = 20\n",
    "pltX, pltY = [], []\n",
    "epoch_end = len(train_loader) - 1\n",
    "for epoch in range(num_epochs):\n",
    "    print('------------Epoch:%d-------------' % epoch)\n",
    "    pltX.append(epoch)\n",
    "    for iteration, data in enumerate(train_loader):\n",
    "        x, _ = data                               # 读入图像数据，只是用x就行\n",
    "        x = x.to(device)                          # 转换数据类型\n",
    "#         x = x.type(torch.cuda.FloatTensor)\n",
    "\n",
    "        _, out = autoencoder(x)                      # (N, 28, 28)\n",
    "        loss = criterion(out, x)        # 计算L2损失\n",
    "#         print(loss)\n",
    "        print_loss = loss.data.item()             # tensor转换为一个数\n",
    "        \n",
    "        # 优化模型\n",
    "        optimizer.zero_grad()                     # 梯度归零\n",
    "        loss.backward()                           # 反向传播\n",
    "        optimizer.step()                          # 更新参数\n",
    "        \n",
    "        if iteration % 500 == 0 or iteration == epoch_end:\n",
    "            print('Iter:{:<5} loss:{:.4f}'.format(iteration, loss.data))\n",
    "    pltY.append(print_loss)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x2667634c550>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 绘制loss曲线\n",
    "plt.title('loss function output curve')\n",
    "plt.xlabel('epochs')\n",
    "plt.ylabel('loss')\n",
    "plt.plot(pltX, pltY)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "损失函数很难看，但整体是在下降的，如果增加批次大的大小，或训练更多的epoch可以画出较平滑的图像"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.4 测试与评估模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x266091b55c0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 测试模型性能\n",
    "autoencoder.eval()                              # 模型进入测试模式\n",
    "test_x, _ = next(test_loader.__iter__())        # torch.Size([64, 1, 28, 28])\n",
    "# print(test_x.shape)\n",
    "test_x = test_x.to(device)\n",
    "with torch.no_grad():\n",
    "    _, out = autoencoder(test_x)\n",
    "#     print(out.shape)\n",
    "scale = lambda x:(x-x.min())/(x.max()-x.min())   # 将范围归一化到[0,1]\n",
    "test_x, out = map(scale, [test_x, out])          # 将数值范围缩放到[0,1]便于显示\n",
    "show_number = 5\n",
    "for i in range(show_number):\n",
    "\n",
    "    # 绘制测试的原图\n",
    "    plt.subplot(2, show_number, i+1)\n",
    "    plt.title('original')\n",
    "    test_x_img = test_x[i,0]                     # (28,28)\n",
    "    plt.axis('off')\n",
    "    plt.imshow(test_x_img, cmap='gray')\n",
    "    \n",
    "    # 绘制生成的原图\n",
    "    plt.subplot(2, show_number, show_number+i+1)\n",
    "    plt.title('generate')\n",
    "    out_x_img = out[i,0]\n",
    "    plt.axis('off')\n",
    "    plt.imshow(out_x_img, cmap='gray')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Using matplotlib backend: Qt5Agg\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x2667634ce10>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 将图像显示在jupyter外，方便交互\n",
    "%matplotlib      \n",
    "# 将图像显示在jupyter里\n",
    "# %matplotlib inline\n",
    "from matplotlib import cm\n",
    "from mpl_toolkits.mplot3d import Axes3D\n",
    "autoencoder.cpu()                                  # 使用cpu处理\n",
    "images, labels = next(test_loader.__iter__())      # 读入批次的数据\n",
    "encode, _ = autoencoder(images)                    # encode (N,3)\n",
    "\n",
    "fig = plt.figure()\n",
    "ax = Axes3D(fig)                                   # 创建3D图\n",
    "X = encode.data[:,0].numpy()                       # 创建数据点\n",
    "Y = encode.data[:,1].numpy()\n",
    "Z = encode.data[:,2].numpy()\n",
    "values = labels.numpy()\n",
    "\n",
    "for x, y, z, v in zip(X,Y,Z,values):\n",
    "    c = cm.rainbow(int(255*v/9))                  # 画出颜色\n",
    "    ax.text(x,y,z,v, backgroundcolor=c)           # 选择位置\n",
    "ax.set_xlim(X.min(), X.max())\n",
    "ax.set_ylim(Y.min(), Y.max())\n",
    "ax.set_zlim(Z.min(), Z.max())\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "参考：[廖星宇github](https://github.com/L1aoXingyu/code-of-learn-deep-learning-with-pytorch/blob/master/chapter6_GAN/autoencoder.ipynb)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "总结：\n",
    "1. 解码器部分输出一定要缩放到(-1,1)范围，经过一个tanh()非线性函数处理就行\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. 基于卷积的自编码器\n",
    "使用全连接层作为编码和解码器会丢失一些空间信息，导致重构的图像轮廓是模糊的，使用卷积神经网络会得到更好的效果，使轮廓更加清晰，反卷积公式：\n",
    "$$out = (input-1)*s+w-2*p$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义基于CNN的自编码器\n",
    "class AutoEncoderCNN(nn.Module):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.encoder = nn.Sequential(                                # input (N, 1, 28, 28)\n",
    "            nn.Conv2d(1, 16, kernel_size=3, stride=3, padding=1),    # (N,16,10,10)\n",
    "            nn.BatchNorm2d(16),\n",
    "            nn.ReLU(),\n",
    "            nn.MaxPool2d(2, stride=2),                               # (N,16,5,5)\n",
    "            nn.Conv2d(16, 8, kernel_size=3, stride=2, padding=1),    # (N,8,3,3)\n",
    "            nn.BatchNorm2d(8),\n",
    "            nn.ReLU(),\n",
    "            nn.MaxPool2d(2, stride=1)                                # (N,8,2,2)\n",
    "        )\n",
    "        self.decoder = nn.Sequential(\n",
    "            nn.ConvTranspose2d(8, 16, kernel_size=3, stride=2),      # (N,16,5,5)\n",
    "            nn.ReLU(),\n",
    "            nn.ConvTranspose2d(16, 8, 5, stride=3, padding=1),       # (N,8,15,15)\n",
    "            nn.ReLU(),\n",
    "            nn.ConvTranspose2d(8, 1, 2, stride=2, padding=1),        # (N,1,28,28)\n",
    "            nn.Tanh()                                                # 缩放数据到 (-1,1) \n",
    "        )        \n",
    "        self._init_weights()                                         # 初始化权重和偏置\n",
    "        \n",
    "    def forward(self, x):\n",
    "        encode = self.encoder(x)\n",
    "        decode = self.decoder(encode)\n",
    "        return encode, decode\n",
    "    \n",
    "    def _init_weights(self):\n",
    "        for m in self.modules():\n",
    "            if isinstance(m, nn.Conv2d):\n",
    "                nn.init.kaiming_normal_(m.weight.data)\n",
    "                nn.init.zeros_(m.bias.data)\n",
    "            elif isinstance(m, nn.BatchNorm2d):\n",
    "                nn.init.ones_(m.weight.data)\n",
    "                nn.init.zeros_(m.bias.data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "cnn_autoencoder = AutoEncoderCNN().to(device)\n",
    "criterion = nn.MSELoss()         # L2损失\n",
    "optimizer = optim.Adam(cnn_autoencoder.parameters(), lr=1e-3, weight_decay=1e-5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "------------Epoch:0-------------\n",
      "Iter:0     loss:0.9591\n",
      "Iter:468   loss:0.2769\n",
      "------------Epoch:1-------------\n",
      "Iter:0     loss:0.2664\n",
      "Iter:468   loss:0.1584\n",
      "------------Epoch:2-------------\n",
      "Iter:0     loss:0.1565\n",
      "Iter:468   loss:0.1298\n",
      "------------Epoch:3-------------\n",
      "Iter:0     loss:0.1288\n",
      "Iter:468   loss:0.1259\n",
      "------------Epoch:4-------------\n",
      "Iter:0     loss:0.1131\n",
      "Iter:468   loss:0.1213\n",
      "------------Epoch:5-------------\n",
      "Iter:0     loss:0.1151\n",
      "Iter:468   loss:0.1003\n",
      "------------Epoch:6-------------\n",
      "Iter:0     loss:0.1081\n",
      "Iter:468   loss:0.1010\n",
      "------------Epoch:7-------------\n",
      "Iter:0     loss:0.1113\n",
      "Iter:468   loss:0.1019\n",
      "------------Epoch:8-------------\n",
      "Iter:0     loss:0.1155\n",
      "Iter:468   loss:0.1020\n",
      "------------Epoch:9-------------\n",
      "Iter:0     loss:0.0990\n",
      "Iter:468   loss:0.1047\n",
      "------------Epoch:10-------------\n",
      "Iter:0     loss:0.1054\n",
      "Iter:468   loss:0.0942\n",
      "------------Epoch:11-------------\n",
      "Iter:0     loss:0.0970\n",
      "Iter:468   loss:0.0988\n",
      "------------Epoch:12-------------\n",
      "Iter:0     loss:0.1010\n",
      "Iter:468   loss:0.0900\n",
      "------------Epoch:13-------------\n",
      "Iter:0     loss:0.1014\n",
      "Iter:468   loss:0.0939\n",
      "------------Epoch:14-------------\n",
      "Iter:0     loss:0.0916\n",
      "Iter:468   loss:0.0932\n",
      "------------Epoch:15-------------\n",
      "Iter:0     loss:0.0980\n",
      "Iter:468   loss:0.0874\n",
      "------------Epoch:16-------------\n",
      "Iter:0     loss:0.1026\n",
      "Iter:468   loss:0.0921\n",
      "------------Epoch:17-------------\n",
      "Iter:0     loss:0.0972\n",
      "Iter:468   loss:0.0914\n",
      "------------Epoch:18-------------\n",
      "Iter:0     loss:0.0975\n",
      "Iter:468   loss:0.0940\n",
      "------------Epoch:19-------------\n",
      "Iter:0     loss:0.0985\n",
      "Iter:468   loss:0.0961\n",
      "------------Epoch:20-------------\n",
      "Iter:0     loss:0.0927\n",
      "Iter:468   loss:0.0886\n",
      "------------Epoch:21-------------\n",
      "Iter:0     loss:0.0867\n",
      "Iter:468   loss:0.0925\n",
      "------------Epoch:22-------------\n",
      "Iter:0     loss:0.0963\n",
      "Iter:468   loss:0.0854\n",
      "------------Epoch:23-------------\n",
      "Iter:0     loss:0.0837\n",
      "Iter:468   loss:0.0924\n",
      "------------Epoch:24-------------\n",
      "Iter:0     loss:0.0944\n",
      "Iter:468   loss:0.0913\n",
      "Wall time: 2min 26s\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\ProgramData\\Anaconda3\\lib\\site-packages\\torch\\serialization.py:241: UserWarning: Couldn't retrieve source code for container of type AutoEncoderCNN. It won't be checked for correctness upon loading.\n",
      "  \"type \" + obj.__name__ + \". It won't be checked \"\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "# 开始训练模型\n",
    "num_epochs = 25\n",
    "pltX, pltY = [], []\n",
    "epoch_end = len(train_loader) - 1\n",
    "for epoch in range(num_epochs):\n",
    "    print('------------Epoch:%d-------------' % epoch)\n",
    "    for iteration, data in enumerate(train_loader):\n",
    "        x, _ = data                               # 读入图像数据，只是用x就行\n",
    "        x = x.to(device)                          # 转换数据类型\n",
    "#         x = x.type(torch.cuda.FloatTensor)\n",
    "\n",
    "        _, out = cnn_autoencoder(x)               # (N,1,28, 28)\n",
    "        loss = criterion(out, x)                  # 计算L2损失\n",
    "#         print(loss)\n",
    "        print_loss = loss.data.item()             # tensor转换为一个数\n",
    "        \n",
    "        # 优化模型\n",
    "        optimizer.zero_grad()                     # 梯度归零\n",
    "        loss.backward()                           # 反向传播\n",
    "        optimizer.step()                          # 更新参数\n",
    "        \n",
    "        if iteration % 500 == 0 or iteration == epoch_end:\n",
    "#             pltX.append(epoch)\n",
    "            pltY.append(print_loss)\n",
    "            print('Iter:{:<5} loss:{:.4f}'.format(iteration, loss.data))\n",
    "save_image(out, './image/autoencoder_sample.png')\n",
    "torch.save(cnn_autoencoder, './model/autoencoder.pth')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x23cd85c6630>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x23c86fafef0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 绘制loss曲线\n",
    "import imageio        # 读取图像\n",
    "plt.title('loss function output curve')\n",
    "plt.plot(pltY)        # 每500个迭代记录一次loss\n",
    "plt.show()\n",
    "img = imageio.imread('./image/autoencoder_sample.png')       # (H,W,C)\n",
    "plt.title('sample')\n",
    "plt.axis('off')\n",
    "plt.imshow(img)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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KOJKkHi+II4w9fchQ4YAcMghhwDw9NNPA3D77bcD4bzLRuNqtyJVKPVWtSqrtdZaC4D99tsPCOfSjBkzgNrzBZYPR+hmZonouAhdEcP6668PhMhJakWXraxpbhdFVR/4wAcAOProowEYM2YMAMOHDwdg7bXXBkIkf9111wFw0UUXAfCPf/wDgJdeeglII+qK68ZVq60IWxUp+vvKK68MwAEHHADAmWeeCcDDDz8MwKc+9SkAXn755ZL/g848h/R+0FeN6gYPHgzAgQceWPJ1p512AuDcc88FYObMmUAaOfV2jKji/qjRx3aEbmaWiEJG6KrnXXPNNYEQDQFssskmQMih66uiTuWB48hMeWX9rAjkmWeeKfk/fc1+UhYhp6zjfs973gPAG2+80fO3TTfdFIBrr70WgI022ggIKxbVRoo+dV/bbLMNAJMmTQLg3//+NwAvvvhii55F/jTK0FdF5HE0pp/VvuPGjQNg6NChAMydOxcIban7K9p50lerrroqAIcffjgAn/jEJwDYcsstgTCy0fPWuaX3XUpzWe9973uBcE7Ec0vVomjdXn2NzjXdXv0awGuvvQaE9mtWpZIjdDOzRBQyQld+fPvttwfCJx3AhAkTALj55puBUKExduxYAJ566ikA5s+fD4RIXJGWKjwUiel2d911FwAPPvhg2WPGn57tzBMqQlQ+HEJ+U8/1f//7HxBy4Yqe9NzjvN0LL7wAhDZp5r4cRRW/hnqu8QpIjeCuuuoqAJ5//vmK/9epFE0qN37MMccAITLX33XO6L2gaheNCuO5rE6kEexee+0FhDkozTGpb6hG585mm20GhEqpSh566CEgjHSalb93hG5mlohCReiKDFXjqk9ERQMAW2yxBQC77747AIsXLwbg1ltvLflZFR/65FMEoWhV0eiuu+4KhGhW+folS5aUHV+cE8uTHlPHmf30HzFiBABLly4FYOHChQDcf//9QKgVVq595MiRQIjC9P+KxtoddbazflvzD/vssw8A//rXvwC44YYbgDQqfyDs/6JqnjPOOAOADTbYAAjvk3iUp9dE75+DDjoIgKlTpwKlI9tOo1HvcccdB4TRiEa8tUau8XzCpz/9aQAWLVoEhKxC9ja672ad647QzcwS4Q7dzCwRhUq5aKit4cirr74KhEk7CJNSSi9oMvOOO+4AwgIQpVw0RNaEoe5b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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x23cd8631ba8>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 测试模型性能\n",
    "cnn_autoencoder.eval()                          # 模型进入测试模式\n",
    "test_x, _ = next(test_loader.__iter__())        # torch.Size([64, 1, 28, 28])\n",
    "# print(test_x.shape)\n",
    "test_x = test_x.to(device)\n",
    "with torch.no_grad():\n",
    "    _, out = cnn_autoencoder(test_x)\n",
    "#     print(out.shape)\n",
    "scale = lambda x:(x-x.min())/(x.max()-x.min())   # 将范围归一化到[0,1]\n",
    "test_x, out = map(scale, [test_x, out])          # 将数值范围缩放到[0,1]便于显示\n",
    "show_number = 5\n",
    "for i in range(show_number):\n",
    "\n",
    "    # 绘制测试的原图\n",
    "    plt.subplot(2, show_number, i+1)\n",
    "#     plt.title('original')\n",
    "    test_x_img = test_x[i,0]                     # (28,28)\n",
    "    plt.axis('off')\n",
    "    plt.imshow(test_x_img, cmap='gray')\n",
    "    \n",
    "    # 绘制生成的原图\n",
    "    plt.subplot(2, show_number, show_number+i+1)\n",
    "#     plt.title('generate')\n",
    "    out_x_img = out[i,0]\n",
    "    plt.axis('off')\n",
    "    plt.imshow(out_x_img, cmap='gray')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "test_iter = test_loader.__iter__()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.编码器的输出维度： torch.Size([256, 8, 2, 2])\n",
      "2.解码器的输出维度： torch.Size([256])\n"
     ]
    }
   ],
   "source": [
    "# 导入自编码器的模型\n",
    "autoencoder = torch.load('./model/autoencoder.pth').cpu()                 # 导入模型\n",
    "# 为了增加样本个数，多产生几个批次的特征\n",
    "numbers = 2\n",
    "X_cat, Y_cat = [], []\n",
    "for i in range(numbers):\n",
    "    images, labels = next(test_iter)                                      # (N,1,28,28)\n",
    "    encode, decode = autoencoder(images)\n",
    "    X_cat.append(encode)\n",
    "    Y_cat.append(labels)\n",
    "\n",
    "X_cat, Y_cat = map(lambda x:torch.cat(x, dim=0).clone(), [X_cat, Y_cat])   # 注意使用clone\n",
    "print('1.编码器的输出维度：', X_cat.shape)\n",
    "print('2.解码器的输出维度：', Y_cat.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x23cc2a3df98>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "from sklearn.manifold import TSNE\n",
    "# 使用t-sne可视化数据\n",
    "tsne = TSNE(n_components=2, init='pca', random_state=0)\n",
    "X = tsne.fit_transform(X_cat.data.numpy().reshape(X_cat.shape[0],-1))   # (N, 2) 降维到2维\n",
    "# X = tsne.fit_transform(images.numpy().reshape(128,-1))\n",
    "\n",
    "x_min, x_max = np.min(X, 0), np.max(X, 0)           # 取每列的最大值与最小值\n",
    "X = (X - x_min) / (x_max - x_min)                   # 对数据进行归一化才能更好的可视化\n",
    "plt.figure()\n",
    "ax = plt.subplot(111)\n",
    "if not isinstance(Y_cat, np.ndarray):\n",
    "    Y = Y_cat.numpy()\n",
    "for i in range(X.shape[0]): \n",
    "#     plt.axis('off')\n",
    "    plt.title('t-sne result')\n",
    "    plt.xticks([])\n",
    "    plt.yticks([])\n",
    "    plt.text(X[i,0],X[i,1], str(Y[i]),\n",
    "            color=plt.cm.Set1(Y[i]/10.),\n",
    "            fontdict={'weight':'bold', 'size':9})    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "总结\n",
    "1. 每个样本的损失为 $\\ell(x, y) = L = \\{l_1,\\dots,l_N\\}^\\top, \\quad\n",
    "    l_n = \\left( x_n - y_n \\right)^2$，一般**MSE损失**是将各批次的损失取平均即    \n",
    "$$\\ell = \\frac{1}{N}\\sum_{i=1}^N(x_i - y_i)^2$$    \n",
    "使用`nn.MSELoss()`可以实现上述公式(默认)\n",
    "\n",
    "2. **L2损失**公式：\n",
    "$$\\ell =\\|x-y\\|^2 = \\sum_{i=1}^N(x_i - y_i)^2$$\n",
    "使用`nn.MSELoss(reduction='sum')`表示没有除以N的操作，直接将该批次中各数据的损失$(x_i - y_i)^2$累加，实际中一般会**除以2**，在计算梯度的时候可以使系数变为1，参考[tensorflow l2_loss](https://www.tensorflow.org/api_docs/python/tf/nn/l2_loss)\n",
    "3. 损失函数输出的标量值大小与回传的梯度大小有关，所以最后的损失与学习率乘积的结果回传后可以有效的更新权重，在SGD中损失函数大小可能影响比较大，但Adam算法中有归一化梯度的过程，所以损失值的大小对算法影响较小\n",
    "4. 在使用`torch.load('save_model.pth')`时该文件中必须有实现了该模型的类，否则会报错AttributeError: Can’t get attribute ‘model_name’ on <module ‘main’>"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
